#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include "tokenizer.h"
#include "tokenizer.c"
#include <fcntl.h>


void childSignalHandler(int signum) {
  int status;
  pid_t pid;
  pid = waitpid(-1, &status, WNOHANG);
  if (pid > 0){
    printf("background finished pid %d\n", pid);    
  }
}
 

int fd;
int backgrounding;
int ran ;
char *args[64];
int oldOutfd;
int oldInfd;
int size =0;
int main(int argc, char *argv[], char *envp[])
{
  char buf[1024];
  int pid, status;
  char *argz1[2];
  char *argz2[2];	
  char *file;
  TOKENIZER *tokenizer;
  char *tok;
  oldOutfd = dup(STDOUT_FILENO);
  oldInfd = dup(STDIN_FILENO);
  signal(SIGCHLD, childSignalHandler);
  for (;;) {
    fd = -2;
    backgrounding = 0;
    ran = 0;
    // Prompt for and read a command.
    if(write(STDOUT_FILENO,"[Bowser]",8) < 0){
      perror("writing error");
      _exit(1);
    }	
    //read input
    int chars;
    if((chars = read(0,buf,1024)) < 0){
      perror("reading error");
      _exit(1);
    }
    if (chars == 1024){
      if(buf[chars] != '\n'){//input is too long. 
	if(write(STDOUT_FILENO,"Too long \n",11) < 0){
	  perror("writing error");
	  _exit(1);
	}		
      }
    }
    if (chars <= 1){
      //if user presses enter do nothing ;      
    }
    else{
      // Split the string into tokens.
      buf[chars - 1] ='\0';
      tokenizer = init_tokenizer( buf );
      int k;
      for (k =0 ; k < 64; k++){	
	args[k] = NULL;
      }
      //place the tokens in args
      int j  =0;
      int count =0;
      while( (tok = get_next_token( tokenizer )) != NULL){
	args[j] = tok; 
	j++;
	count++;
      }
      free_tokenizer( tokenizer );
      
      int i;	
      // test for redirect , pipeline and background characters 
      for(i = 0; i < count; i++){
	if (*args[i] == '|'){	
	  int a;	
	  for (a= 0; a<i;a++){	  
	    argz1[a] = args[a];
	    size= a;
	      printf("argz1[a]=%s\n",argz1[a])	;
	     
	  }
	  argz1[size+1]='\0';
	  argz2[0] = args[i + 1];	
	  argz2[1] = '\0';
	
	  printf("argz2[a]=%s\n",*argz2)	;
	  int n = do_pipe(argz1,argz2);
	}else if (*args[i] == '>'){
	  file = args[i+1];
	  do_redirect(file,0);
	  args[i] = NULL;
	  args[i+1] = NULL;
	  i++;
	}else if(*args[i] == '<'){
	  file = args[i+1];
	  int f = do_redirect(file,0);
	  args[i] = NULL;	
	  args[i+1] = NULL;
	  i++;
	}else if (*args[i] == '&'){
	  backgrounding = 1;
	  args[i] = NULL;
	}
      }
      //execute command	if it has not been executed by pipeline.
      if (ran == 0){      
	// Get a child process.
	if ((pid = fork()) < 0) {
	  perror("fork error");
	  _exit(1);
	}      
	// The child executes the code inside the if.
	if (pid == 0) {
	  execvp(args[0], args);
	  perror(*args);
	  _exit(1);        
	}
	//The parent executes the wait
	else if (pid > 0){
	  if (backgrounding == 0) { 
	    waitpid(pid, &status, 0);	
	  }
	  if(fd != -2){// if redirect file was open dup stdout back. 
	    dup2(oldOutfd, STDOUT_FILENO);
	    dup2(oldInfd, STDIN_FILENO);		
	  }	  
	}	
      }
    }			
  }
}
int do_pipe(char *argv1[],char *argv2[])   {
  int pipefd[2];
  pid_t cpid;
  char buf;
  char i;
  ran = 1;
  //create pipe
  if (pipe(pipefd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
  }
  //fork child and parent to attatch to pipeline
  cpid = fork();
  if (cpid == -1) {
    perror("fork");
    exit(EXIT_FAILURE);
  }  
  if (cpid == 0) {    // Child writes to pipe

   close(STDOUT_FILENO);
    dup2( pipefd[1],STDOUT_FILENO);   
     close(pipefd[0]);          // Close unused write end 
     	
    execvp(argv1[0], argv1);

 } else {            // Parent reads from pipe    
            // Close unused read end      
     close(STDIN_FILENO);
    dup2(pipefd[0],STDIN_FILENO );
     close(pipefd[1]); 
 //   wait(NULL); //wait for child
	 execvp(argv2[0], argv2);   
  }
  return 0;
}
int do_redirect(char *file, int mode) {
  //Open the file and dup it to in or out
  if (mode == 0){ //dup file to out
    fd = open(file, O_WRONLY | O_CREAT, 0644);
    dup2(fd, STDOUT_FILENO);
  } else if (mode == 1){//dup file to in
    fd = open(file, O_RDONLY , 0644);
    dup2(fd, STDIN_FILENO);
  }else{
    printf(" redirection error");
  }
  return 0;
}
